目前比较常用的定时任务解决方案一般就是Spring Quartz和Task
spring-quartz
spring-quartz只是spring对quartz的一个包装而已。其实现是在spring-context-support中
- 特点
- 默认多线程异步执行
- 单个任务时,在上一个调度未完成时,下一个调度时间到时,会另起一个线程开始新的调度。业务繁忙时,一个任务会有多个调度,可能导致数据处理异常
- 多个任务时,任务之间没有直接影响,多任务执行的快慢取决于CPU的性能
- 使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21<bean id="job" class=" xx.xx.xx.Job" />
<bean id="cronTask" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="job" />
<property name="targetMethod" value="runWork" />
<!-- false表示job不会并发执行,默认为true-->
<property name="concurrent" value="false" />
</bean>
<!—配置触发器-->
<bean id="doWork" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="cronTask" />
<!—每天凌晨0点1分执行-->
<property name="cronExpression" value="0 01 00 * * ?" />
</bean>
<!—最后配置调度工厂-->
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref local="doWork"/>
</list>
</property>
</bean>
spring-task
Spring从3.0开始增加了自己的任务调度器,它是通过扩展java.util.concurrent包下面的类来实现的,也称spring-schedule
- 特点
- 默认单线程同步执行
- 单个任务时,当前次的调度完成后,再执行下一次任务调度
- 多个任务时,一个任务执行完成后才会执行下一个任务。若需要任务能够并发执行,需手动设置线程池
- 默认单线程同步执行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.0.xsd">
<task:annotation-driven />
<bean id="myTask" class="me.changjie.task.MyTask"></bean>
<!--<task:scheduler id="scheduler" pool-size="5" />-->
<!--<task:scheduled-tasks scheduler="scheduler">-->
<task:scheduled-tasks>
<!--两个任务间隔10s执行-->
<task:scheduled ref="myTask" method="method1" cron="0 33 13 * * ?" />
<task:scheduled ref="myTask" method="method2" cron="10 33 13 * * ?"/>
</task:scheduled-tasks>
</beans>
1 | public class MyTask { |
输出1
2
3
4method1 execute thread:pool-1-thread-1
method1 execute time:2018-10-19 13:33:00
method2 execute thread:pool-1-thread-1
method2 execute time:2018-10-19 13:33:20
- 设置线程池使其任务并行
1 | <beans xmlns="http://www.springframework.org/schema/beans" |
输出1
2
3
4method1 execute thread:scheduler-1
method1 execute time:2018-10-19 13:36:00
method2 execute thread:scheduler-2
method2 execute time:2018-10-19 13:36:10
对比
易用性
- spring-quartz配置较复杂(任务、触发器、调度工厂),但拥有spring-task所有的功能
- spring-task配置较简单,但是默认单线程同步,为了避免任务阻塞,最好配置成线程池异步执行
异常处理
- Quartz的某次执行任务过程中抛出异常,不影响下一次任务的执行,当下一次执行时间到来时,定时器会再次执行任务
- SpringTask不同,一旦某个任务在执行过程中抛出异常,则整个定时器生命周期就结束,以后永远不会再执行定时器任务,所以最好全范围catch掉